
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       rcprotocol_backend.c
  * @author     baiyang
  * @date       2022-6-11
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include "rc_protocol.h"
#include "rcprotocol_backend.h"

#include <rc_channel/rc_channel.h>
#include <common/gp_math/gp_mathlib.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void rcprotocol_backend_ctor(rcprotocol_backend_t backend, rcprotocol_backend_ops_t ops)
{
    backend->ops = ops;

    backend->rssi = -1;
    backend->rx_link_quality = -1;

    backend->rc_input_count = 0;
    backend->last_rc_input_count = 0;
    backend->_num_channels = 0;
}

bool rcprotocol_backend_new_input(rcprotocol_backend_t backend)
{
    bool ret = backend->rc_input_count != backend->last_rc_input_count;
    if (ret) {
        backend->last_rc_input_count = backend->rc_input_count;
    }
    return ret;
}

uint8_t rcprotocol_backend_num_channels(rcprotocol_backend_t backend)
{
    return backend->_num_channels;
}

uint16_t rcprotocol_backend_read(rcprotocol_backend_t backend, uint8_t chan)
{
    return backend->_pwm_values[chan];
}

void rcprotocol_backend_read2(rcprotocol_backend_t backend, uint16_t *pwm, uint8_t n)
{
    if (n >= MAX_RCIN_CHANNELS) {
        n = MAX_RCIN_CHANNELS;
    }
    rt_memcpy(pwm, backend->_pwm_values, n*sizeof(pwm[0]));
}

/*
  provide input from a backend
 */
// default rssi=-1, rx_link_quality=-1
void rcprotocol_backend_add_input(rcprotocol_backend_t backend, uint8_t num_values, uint16_t *values, bool in_failsafe, int16_t _rssi, int16_t _rx_link_quality)
{
    num_values = MIN(num_values, MAX_RCIN_CHANNELS);
    rt_memcpy(backend->_pwm_values, values, num_values*sizeof(uint16_t));
    backend->_num_channels = num_values;
    backend->rc_frame_count++;
    rcprotocol._failsafe_active = in_failsafe;

    if (rcs_ignore_rc_failsafe()) {
        in_failsafe = false;
    }

    if (!in_failsafe) {
        backend->rc_input_count++;
    }
    backend->rssi = _rssi;
    backend->rx_link_quality = _rx_link_quality;
}

/*
  decode channels from the standard 11bit format (used by CRSF, SBUS, FPort and FPort2)
  must be used on multiples of 8 channels
*/
void rcprotocol_backend_decode_11bit_channels(const uint8_t* data, uint8_t nchannels, uint16_t *values, uint16_t mult, uint16_t div, uint16_t offset)
{
#define CHANNEL_SCALE(x) (((int32_t)(x) * mult) / div + offset)
    while (nchannels >= 8) {
        const struct Channels11Bit_8Chan* channels = (const struct Channels11Bit_8Chan*)data;
        values[0] = CHANNEL_SCALE(channels->ch0);
        values[1] = CHANNEL_SCALE(channels->ch1);
        values[2] = CHANNEL_SCALE(channels->ch2);
        values[3] = CHANNEL_SCALE(channels->ch3);
        values[4] = CHANNEL_SCALE(channels->ch4);
        values[5] = CHANNEL_SCALE(channels->ch5);
        values[6] = CHANNEL_SCALE(channels->ch6);
        values[7] = CHANNEL_SCALE(channels->ch7);

        nchannels -= 8;
        data += sizeof(*channels);
        values += 8;
    }
}

/*
  optionally log RC input data
 */
void rcprotocol_backend_log_data(enum rcprotocol_t prot, uint32_t timestamp, const uint8_t *data, uint8_t len)
{

}

uint32_t rcprotocol_backend_get_rc_protocols_mask(void) {
    return rcprotocol.rc_protocols_mask;
}

// get UART for RCIN, if available. This will return false if we
// aren't getting the active RC input protocol via the uart
rt_device_t rcprotocol_backend_get_UART(void) {
    return rcprotocol._detected_with_bytes?rcprotocol.added.uart:NULL;
}

// get an available uart regardless of whether we have detected a protocol via it
rt_device_t rcprotocol_backend_get_available_UART(void) {
    return rcprotocol.added.uart;
}

// return true if we have a uart available for protocol handling.
bool rcprotocol_backend_have_UART(void) {
    return rcprotocol.added.uart != NULL;
}

/*------------------------------------test------------------------------------*/


